package DCSource.Streams;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

import DCSource.Crypt.Security;

public class aSecurityInputStream extends InputStream{
	private KeyPair keys;
	private InputStream reader;
	private ByteArrayOutputStream EncodedChunk = new ByteArrayOutputStream();
	private int vSize = 0;
	public aSecurityInputStream(KeyPair pair, InputStream reader) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException{
		keys = pair;
		this.reader = reader;
		vSize = Security.encrypt("a".getBytes(), pair.getPublic()).length;
	}
	private void getNextChunks(int getSize) throws IOException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException{
		byte[] chunk = new byte[vSize];
		int csize = 0;
		boolean can = true;
		while (getSize>EncodedChunk.toByteArray().length & can){
			csize = reader.read(chunk);
			if (csize!=-1){
				EncodedChunk.write(Security.decrypt(chunk, keys.getPrivate(), csize));
			}else{
				can = false;
			}
			}
	}
	private int contentfull(byte[] b, int off, int len) throws IOException{
		EncodedChunk.flush();
		ByteArrayInputStream in = new ByteArrayInputStream(EncodedChunk.toByteArray());
		EncodedChunk.reset();
		byte[] back = new byte[0];
		if (len<in.available()){
			back = new byte[in.available()-len];
		}
		int readed = in.read(b,off,len);
		in.read(back);
		in.close();
		EncodedChunk.write(back);
		return readed;
	}
	public int read(byte[] b) throws IOException{
		int getSize = b.length;
		int readed = -1;
		if (getSize>EncodedChunk.toByteArray().length){
			try{
				getNextChunks(getSize);
			}catch(Exception err){}
		}
		readed = contentfull(b,0,getSize);
		return readed;
	}
	public int read(byte[] b, int off, int len) throws IOException{
		int getSize = len;
		int readed = -1;
		if (getSize>EncodedChunk.toByteArray().length){
			try{
				getNextChunks(getSize);
			}catch(Exception err){}
		}
		readed = contentfull(b,off,getSize);
		return readed;
	}
	public boolean markSupported(){
		return false;
	}
	public int available() throws IOException{
		return (int) ((reader.available())-(11*(reader.available()/vSize)));
	}
	public void reset() throws IOException{
		reader.reset();
		EncodedChunk.reset();
	}
	public long skip(long i) throws IOException{
		long skipped = i;
		ByteArrayInputStream r = new ByteArrayInputStream(EncodedChunk.toByteArray());
		skipped-=r.skip(i);
		if (i>0){
			try{
				getNextChunks((int) skipped);
			}catch(Exception err){}
		}
		contentfull(new byte[(int)i],0,(int)i);
		return skipped;
	}
	public void close() throws IOException{
		EncodedChunk.close();
		reader.close();
	};
	public int read() throws IOException {
		return 0;
	}
}
